import logging
import logging.handlers
from pathlib import Path
import sys
import os

from config.app_config import AppConfig
from core.config import Config
from core.singleton_meta import SingletonMeta
from core.util.helper import Helper
import json
from colorama import Fore, Style


class ColoredFormatter(logging.Formatter):
    """彩色日志格式化器"""

    COLORS = {
        'DEBUG': Fore.CYAN,
        'INFO': Fore.GREEN,
        'WARNING': Fore.YELLOW,
        'ERROR': Fore.RED,
        'CRITICAL': Fore.RED,
    }

    def format(self, record):
        level_color = self.COLORS.get(record.levelname, '')
        formatted = super().format(record)
        if level_color:
            level_name = record.levelname
            colored_level = f'{level_color}{level_name}{Style.RESET_ALL}'
            formatted = formatted.replace(level_name, colored_level)

        return formatted


class Logger(metaclass=SingletonMeta):
    _is_init: bool = False
    service_name: str = Config.get(AppConfig).app_name

    @classmethod
    def init(cls):
        if cls._is_init:
            return

        root_logger = logging.getLogger()
        root_logger.setLevel(logging.INFO)
        root_logger.handlers.clear()

        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(logging.INFO)

        console_formatter = ColoredFormatter(
            '%(asctime)s | %(levelname)-6s | %(name)s:%(funcName)s:%(lineno)d - %(message)s', datefmt='%Y-%m-%d %H:%M:%S'
        )
        console_handler.setFormatter(console_formatter)
        root_logger.addHandler(console_handler)

        # 创建 INFO 级别文件处理器
        info_file_handler = cls._create_file_handler('INFO', logging.INFO, logging.WARNING)
        root_logger.addHandler(info_file_handler)

        # 创建 ERROR 级别文件处理器
        error_file_handler = cls._create_file_handler('ERROR', logging.ERROR, logging.CRITICAL)
        root_logger.addHandler(error_file_handler)
        cls._is_init = True

    @classmethod
    def _create_file_handler(cls, level: str, min_level: int, max_level: int) -> logging.Handler:
        """创建文件日志处理器"""
        # 1. 获取日志文件路径
        log_file = cls._get_log_file(level)

        # 2. 创建 RotatingFileHandler 实现文件轮转
        file_handler = logging.handlers.RotatingFileHandler(
            filename=log_file,
            maxBytes=50 * 1024 * 1024,  # 50 MB
            backupCount=10,  # 保留10个备份文件
            encoding='utf-8',
        )

        # 3. 设置日志级别
        file_handler.setLevel(min_level)

        # 4. 创建日志过滤器
        class LevelFilter(logging.Filter):
            def filter(self, record):
                return min_level <= record.levelno <= max_level

        file_handler.addFilter(LevelFilter())

        # 5. 设置 JSON 格式
        json_formatter = cls._create_json_formatter()
        file_handler.setFormatter(json_formatter)

        return file_handler

    @classmethod
    def _create_json_formatter(cls) -> logging.Formatter:
        """创建 JSON 格式的日志格式化器"""

        class JsonFormatter(logging.Formatter):
            def format(self, record: logging.LogRecord):
                # 2. 构建 JSON 日志记录
                log_data = {
                    'timestamp': self.formatTime(record),
                    'level': record.levelname,
                    'service': cls.service_name,
                    'thread': record.thread,
                    'message': record.getMessage(),
                    'logger': record.module,
                    'file': record.pathname,
                    'function': record.funcName,
                    'line': record.lineno,
                }
                if hasattr(record, 'otelTraceID'):
                    log_data['trace_id'] = record.otelTraceID  # type: ignore
                if hasattr(record, 'otelSpanID'):
                    log_data['span_id'] = record.otelSpanID  # type: ignore

                # 3. 如果有异常信息，添加到日志中
                if record.exc_info:
                    log_data['exception'] = self.formatException(record.exc_info)

                # 4. 转换为 JSON 字符串
                return json.dumps(log_data, ensure_ascii=False)

        return JsonFormatter()

    @classmethod
    def _get_log_file(cls, level: str):
        level = level.lower()
        paths = ['logs', cls.service_name, level, f'{cls.service_name}-{level}.log']
        if Config.get(AppConfig).is_prod_or_test():
            log_file = Path('/').joinpath('data', *paths)
        else:
            log_file = Helper.with_root_path(paths)
        log_file = str(log_file)
        os.makedirs(os.path.dirname(log_file), exist_ok=True, mode=0o644)
        return log_file

    @classmethod
    def get(cls, name: str | None = None) -> logging.Logger:
        cls.init()
        return logging.getLogger(cls.service_name if name is None else name)


def init():
    """初始化日志系统"""
    Logger.init()
